home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume2 / cpg+mdep3 < prev    next >
Encoding:
Internet Message Format  |  1986-11-30  |  33.6 KB

  1. From: ihnp4!amdcad!idi!bene!luke!steven
  2. Subject: cpg revisited
  3. Reply-To: steven@luke.UUCP (Steven List)
  4. Newsgroups: mod.sources
  5. Approved: john@genrad.UUCP
  6.  
  7. Mod.sources:  Volume 2, Issue 1
  8. Submitted by: steven@luke.UUCP (Steven List)
  9.  
  10.  
  11. This is a reposting of my C source listing formatter, `cpg'.  The main
  12. reason for the reposting is that someone actually asked for another
  13. command line option.  The addition is a `-b' option, which causes the
  14. use of only the basename portion of the file name in page headers.
  15.  
  16. I also included a little conditional preprocessor stuff for those pieces
  17. that I know (believe) are version dependent.  So, if you -DBSD, strchr
  18. and strrchr become index and rindex.  If anybody finds anything else
  19. that is version dependent (and if they have the fix), please send it to
  20. me.
  21.  
  22. I found that the changes involved enough of the source file that posting
  23. a patch would have been almost as large as reposting.  So here are the
  24. manual page and source updated.
  25.  
  26. Thanks to Bill Turner (hpdsd!hppsd2!bill) for the suggestion (he got an
  27. early copy of this article for his efforts).
  28.  
  29. ***
  30. *  Steven List @ Benetics Corporation, Mt. View, CA
  31. *  {cdp,greipa,idi,oliveb,sun,tolerant}!bene!luke!steven
  32. ***
  33. --------------------------- Cut Here -----------------------------------
  34. #! /bin/sh
  35. # This is a shell archive, meaning:
  36. # 1. Remove everything above the #! /bin/sh line.
  37. # 2. Save the resulting text in a file.
  38. # 3. Execute the file with /bin/sh (not csh) to create the files:
  39. #    cpg.1
  40. #    cpg.c
  41. # This archive created: Mon Jun 24 20:19:05 1985
  42. export PATH; PATH=/bin:$PATH
  43. echo shar: extracting "'cpg.1'" '(5283 characters)'
  44. if test -f 'cpg.1'
  45. then
  46.     echo shar: will not over-write existing file "'cpg.1'"
  47. else
  48. sed 's/^    X//' << \SHAR_EOF > 'cpg.1'
  49.     X.so /b/doc/nroffmacros/manmac
  50.     X.TH "cpg" "1" "Benetics Local"
  51.     X.ds C \fIcpg\fR
  52.     X.tr ~  
  53.     X.fi
  54.     X.ad b
  55.     X.SH NAME
  56.     Xcpg - C source listing formatter
  57.     X.SH SYNOPSIS
  58.     Xcpg [ -b<asename> ] [ -t tabstop ] [ file... ]
  59.     X.SH DESCRIPTION
  60.     X\*C is a C language source listing formatter.  It employs certain
  61.     Xtriggers to perform its formatting.  Those same triggers may be used to
  62.     Xextract in-line documentation to create documentation.  At the end of
  63.     Xthe listing produced by \*C is a table of contents of all files and
  64.     Xfunctions contained in the current listing.  The table of contents is
  65.     Xsorted alphabetically by function and file.
  66.     X.P
  67.     XThe listing produced by \*C includes on each line a line number.  On each
  68.     Xline containing any braces ({}), there will also be a
  69.     Xnesting level indicator.  The nesting level indicator includes a number
  70.     X(the current nesting level) and a directional character.  The
  71.     Xdirectional characters are:
  72.     X.IP > 6
  73.     XThe nesting level increased on this line
  74.     X.IP < 6
  75.     XThe nesting level decreased on this line
  76.     X.IP * 6
  77.     XThe nesting level changed both ways, with a net change of zero
  78.     X.P
  79.     XThe triggers that \*C recognizes are itemized below.  Each must appear
  80.     Xin column 1.
  81.     X.TP
  82.     X<formfeed>
  83.     XA formfeed will cause a new page to be started with a full header.
  84.     X.TP
  85.     X/*F filename *<anything>
  86.     XThe file name may be specified in a comment preceding a descriptive
  87.     Xheader block.  The filename argument must be delimited by asterisks in
  88.     Xthe trigger.  The filename will appear in all page headings up to the
  89.     Xnext filename trigger or the next file.  A filename comment block
  90.     X\fBmust\fR be terminated by the endofblock trigger (see below).
  91.     XThis trigger will print as a line in the listing.  This trigger causes
  92.     Xthe start of a new page (form feed) in the listing, with printing of the
  93.     Xpage header including the current file name.
  94.     X.TP
  95.     X/*H funcname *<anything>
  96.     XThe function name may be specified in a comment preceding a descriptive
  97.     Xheader block.  The funcname argument must be delimited by asterisks in
  98.     Xthe trigger.  The funcname will appear in all page headings up to the
  99.     Xnext funcname trigger or the next file.  A funcname comment block
  100.     X\fBmust\fR be terminated by the endofblock trigger (see below).
  101.     XThis trigger will print as a line in the listing.  This trigger causes
  102.     Xthe start of a new page (form feed) in the listing, with printing of the
  103.     Xpage header including the current function name.
  104.     X.TP
  105.     X/*E*/
  106.     XThis is the endofblock trigger.  Everything between the last filename or
  107.     Xfuncname trigger and the endofblock trigger will be passed straight
  108.     Xthrough by \*C without evaluation of nesting levels, comments, or quoted
  109.     Xstrings.  Thus, a header block is treated as one long comment by \*C.
  110.     XThis trigger will print as a line in the listing.
  111.     X.TP
  112.     X/*P*/
  113.     XThis is a page eject trigger.  It will not print in the listing, but
  114.     Xwill be counted for line numbering purposes.  This trigger causes the
  115.     Xpage heading, title, and subtitle to be reprinted based on their current
  116.     Xvalues (see title and subtitle below).
  117.     X.TP
  118.     X/*S <text> */
  119.     XThis is the subtitle trigger.  It determines the contents of the second
  120.     Xtitle line on the page header.  All characters after the initial space
  121.     Xand up to but not including the following asterisk (required) are
  122.     Xincluded as part of the subtitle.  This trigger will not print in the
  123.     Xlisting but will be counted for line numbering purposes.
  124.     X.TP
  125.     X/*T <text> */
  126.     XThis is the title trigger.  It determines the contents of the first
  127.     Xtitle line on the page header.  All characters after the initial space
  128.     Xand up to but not including the following asterisk (required) are
  129.     Xincluded as part of the title.  This trigger will not print in the
  130.     Xlisting but will be counted for line numbering purposes.
  131.     X.SS Options
  132.     X.IP "-b" 16
  133.     XThe basename option causes \fIcpg\fR to use only the basename portion of
  134.     Xthe filename (whether obtained from the fileheader trigger or the
  135.     Xcurrent filename) in page headers as well as the table of contents.
  136.     XThus, if a file is printed using "cpg -bt4 `pwd`/xyz.c", only "xyz.c"
  137.     Xwill show up in the page header.
  138.     X.IP "-t tabstop" 16
  139.     XThe tabstop argument to the -t option specifies how to expand tabs.  The
  140.     Xexpansion is performed automatically with a tabstop of 8 if none is
  141.     Xspecified.
  142.     X.SS Arguments
  143.     X.IP file 16
  144.     XAny number of file names may be specified on the command line (within
  145.     Xlimits set by whichever shell is used).  Each file will be formatted and
  146.     Xits name added to the table of contents.  If no file names are
  147.     Xspecified, \*C will read the standard input.
  148.     X.SH FILES
  149.     X.IP "/tmp/toc_XXXXXX" 20
  150.     Xtemporary file for building the table of contents.
  151.     X.SH "SEE ALSO"
  152.     Xdtab(1), nl(1), pr(1), sort(1)
  153.     X.SH NOTES
  154.     XThis tool was developed at Benetics Corporation.
  155.     X.P
  156.     XA side note: \*C also properly processes comments in shell scripts and
  157.     Xmakefiles.  These comments are correctly handled when the comment
  158.     Xcharacter (# or :) is the first nonblank character on a line.  In order
  159.     Xto facilitate documentation of shell scripts, \*C recognizes the
  160.     Xsequences #{ and #} as the beginning and ending of nesting, and treats
  161.     Xthem as it does in C program sources.  Thus lengthy for, if, while, and
  162.     Xcase statements may be more clearly documented as to nesting levels,
  163.     Xparticulary in shell scripts.
  164.     X.SH AUTHOR
  165.     X.na
  166.     X.nf
  167.     XSteven M. List
  168.     XBenetics Corporation
  169.     XMountain View, CA.
  170.     X{cdp,idi,greipa,oliveb,sun,tolerant}!bene!luke!steven
  171. SHAR_EOF
  172. if test 5283 -ne "`wc -c < 'cpg.1'`"
  173. then
  174.     echo shar: error transmitting "'cpg.1'" '(should have been 5283 characters)'
  175. fi
  176. fi # end of overwriting check
  177. echo shar: extracting "'cpg.c'" '(24738 characters)'
  178. if test -f 'cpg.c'
  179. then
  180.     echo shar: will not over-write existing file "'cpg.c'"
  181. else
  182. sed 's/^    X//' << \SHAR_EOF > 'cpg.c'
  183.     X/*Tcpg - c program source listing formatter */
  184.     X/*F cpg.c **********************************************************
  185.     X *
  186.     X *                           cpg.c
  187.     X *
  188.     X *    DESCRIPTION OF FILE CONTENTS:
  189.     X *      C source program listing formatter source.
  190.     X *
  191.     X *  Cpg provides the facility to print out a C language source file
  192.     X *  with headers, nesting level indicators, and table of contents.
  193.     X *  It makes use of "triggers" for page headings, titles and
  194.     X *  subtitles, and pagination.  It also recognizes function
  195.     X *  declarations and form feeds and treats them appropriately.
  196.     X *
  197.     X *******************************************************************/
  198.     X/*E*/
  199.     X/*S includes, defines, and globals */
  200.     X/*P*/
  201.     X#include <stdio.h>
  202.     X#include    <ctype.h>
  203.     X#include    <time.h>
  204.     X
  205.     X#define EQ ==
  206.     X#define NE !=
  207.     X#define GT >
  208.     X#define GE >=
  209.     X#define LT <
  210.     X#define LE <=
  211.     X#define OR ||
  212.     X#define AND &&
  213.     X
  214.     X#define TRUE 1
  215.     X#define FALSE 0
  216.     X#define YES 1
  217.     X#define NO 0
  218.     X
  219.     X#define SPACE ' '
  220.     X#define NUL '\0'
  221.     X
  222.     Xtypedef short   BOOL;
  223.     X
  224.     X#define INULL -32768
  225.     X#define LNULL -2147483648
  226.     X
  227.     X#define MAX(a,b) ((a) > (b) ? (a) : (b))
  228.     X#define MIN(a,b) ((a) < (b) ? (a) : (b))
  229.     X#define ABS(a) ((a) >= 0 ? (a) : -(a))
  230.     X
  231.     X#define LINESINHEAD 6
  232.     X#define LPP 60
  233.     X#define MAXWIDTH    130
  234.     X
  235.     X#define notend(ll) ((ll[0] EQ SLASH AND ll[1] EQ STAR AND ll[2] EQ 'E') ? FALSE : TRUE)
  236.     X#define SLASH   '/'
  237.     X#define STAR    '*'
  238.     X#define DQUOTE '"'
  239.     X#define SQUOTE '\''
  240.     X#define BSLASH '\\'
  241.     X
  242.     X#ifdef BSD
  243.     X#define strrchr rindex
  244.     X#define strchr index
  245.     X#endif BSD
  246.     X
  247.     Xextern char *strrchr ();
  248.     Xextern char *strchr ();
  249.     X
  250.     Xchar    *basename ();
  251.     X
  252.     Xchar    tim_lin[40];
  253.     Xchar    *file_name;
  254.     Xchar    fh_name[50] = "";
  255.     Xchar    fnc_name[40] = "";
  256.     Xchar    subttl[70] = "";
  257.     Xchar    title[70] = "";
  258.     Xchar    tocname[] = "/tmp/toc_XXXXXX";
  259.     X
  260.     Xint     nlvl = 0;
  261.     X
  262.     Xint     page_line = LPP+1;
  263.     Xint     pageno = 1;
  264.     X
  265.     Xint     tabstop = 8;
  266.     X
  267.     Xint     infunc = FALSE;
  268.     Xint     logging = 0;
  269.     Xint     BASENAME = FALSE;
  270.     X
  271.     Xint     incomment = FALSE;
  272.     Xint     insquote = FALSE;
  273.     Xint     indquote = FALSE;
  274.     X
  275.     Xchar    specline = FALSE;
  276.     X
  277.     XFILE    *tocfile;
  278.     XFILE    *fd;
  279.     X
  280.     Xchar    *pgm;
  281.     X
  282.     Xchar    *ReservedWord[]  = { 
  283.     X     "auto", "bool", "break", "case", "char", "continue",
  284.     X     "default", "do", "double", "else", "entry", "enum",
  285.     X     "extern", "float", "for", "goto", "if",
  286.     X     "int", "long", "register", "return", "short",
  287.     X     "sizeof", "static", "struct", "switch",
  288.     X     "typedef", "union", "unsigned", "void", "while",
  289.     X     NULL };
  290.     X
  291.     X/*S main function */
  292.     X/*Hmain */
  293.     X/*E*/
  294.     X
  295.     Xmain (ac, av)
  296.     Xint     ac;
  297.     Xchar    **av;
  298.     X{
  299.     X    char    *std_input = "standard input";  /* input file name      */
  300.     X
  301.     X    long    cur_time;               /* place for current raw time   */
  302.     X
  303.     X    long    *time();                /* return raw time from system  */
  304.     X
  305.     X    register int i;                 /* temporary for indexes, etc.  */
  306.     X
  307.     X    struct tm *tim;                 /* return from localtime        */
  308.     X    struct tm *localtime ();
  309.     X
  310.     X    char    cmdbuf[40];             /* place to format sort command */
  311.     X
  312.     X    extern char *optarg;            /* option argument pointer      */
  313.     X    extern int   optind;            /* option index                 */
  314.     X
  315.     X    pgm = basename (av[0]);
  316.     X
  317.     X    while ((i = getopt (ac, av, "bl:t:")) NE EOF)
  318.     X    {
  319.     X        switch (i)
  320.     X        {
  321.     X            case    'b':
  322.     X                BASENAME = TRUE;
  323.     X                break;
  324.     X            case    'l':
  325.     X                logging = atoi (optarg);
  326.     X                break;
  327.     X            case    't':
  328.     X                tabstop = atoi (optarg);
  329.     X                break;
  330.     X            default:
  331.     X                fprintf (stderr,
  332.     X        "usage: %s [ -b<asename> ] [ -t <tabstop> ] [ files... ]\n",
  333.     X                        pgm);
  334.     X        }
  335.     X    }
  336.     X
  337.     X    /* ------------------------------------------------------------ */
  338.     X    /* set up the date/time portion of page headings                */
  339.     X    /* ------------------------------------------------------------ */
  340.     X
  341.     X    time(&cur_time);
  342.     X
  343.     X    tim = localtime (&cur_time);
  344.     X    sprintf (tim_lin, "Printed: %02d/%02d/%02d at %2d:%02d %s",
  345.     X        tim->tm_mon + 1, tim->tm_mday, tim->tm_year,
  346.     X        tim->tm_hour GT 12 ? tim->tm_hour - 12 : tim->tm_hour,
  347.     X        tim->tm_min,
  348.     X        tim->tm_hour GE 12 ? "PM" : "AM" );
  349.     X
  350.     X    /* ------------------------------------------------------------ */
  351.     X    /* create the temporary file for the table of contents          */
  352.     X    /*   don't bother if output is to a terminal                    */
  353.     X    /* ------------------------------------------------------------ */
  354.     X
  355.     X    mktemp (tocname);
  356.     X    if (!isatty (1))
  357.     X    {
  358.     X        tocfile = fopen (tocname, "w");
  359.     X        if (!tocfile)
  360.     X        {
  361.     X            fprintf (stderr, "%s: unable to create tocfile %s\n",
  362.     X                pgm, tocname);
  363.     X            exit (2);
  364.     X        }
  365.     X    }
  366.     X
  367.     X    /* ------------------------------------------------------------ */
  368.     X    /* if no file names, read standard input                        */
  369.     X    /* ------------------------------------------------------------ */
  370.     X
  371.     X    if (optind EQ ac)
  372.     X    {
  373.     X        fd = stdin;
  374.     X        file_name = std_input;
  375.     X        dofile (fd);
  376.     X    }
  377.     X    else
  378.     X    {
  379.     X    /* ------------------------------------------------------------ */
  380.     X    /* process each file named on the command line                  */
  381.     X    /* ------------------------------------------------------------ */
  382.     X
  383.     X        for (i = optind; i LT ac; i++)
  384.     X        {
  385.     X    /* ------------------------------------------------------------ */
  386.     X    /* special file name `-' is standard input                      */
  387.     X    /* ------------------------------------------------------------ */
  388.     X
  389.     X            if (strcmp (av[i], "-") EQ 0)
  390.     X            {
  391.     X                fd = stdin;
  392.     X                file_name = std_input;
  393.     X            }
  394.     X            else
  395.     X            {
  396.     X                fd = fopen (av[i], "r");
  397.     X                if (fd EQ NULL)
  398.     X                {
  399.     X                    fprintf (stderr,
  400.     X                        "cpg: unable to open %s\n", av[i]);
  401.     X                }
  402.     X            }
  403.     X            if (fd NE NULL)
  404.     X            {
  405.     X                if (BASENAME) strcpy (fh_name, basename (av[i]));
  406.     X                else strcpy (fh_name, av[i]);
  407.     X                file_name = av[i];
  408.     X                dofile (fd);
  409.     X                fclose (fd);
  410.     X            }
  411.     X        }
  412.     X    }
  413.     X
  414.     X    fflush (stdout);
  415.     X
  416.     X    /* ------------------------------------------------------------ */
  417.     X    /* sort and print the table of contents - straight alpha order  */
  418.     X    /* on function and file name                                    */
  419.     X    /* ------------------------------------------------------------ */
  420.     X
  421.     X    if (!isatty (1))
  422.     X    {
  423.     X        fclose (tocfile);
  424.     X        sprintf (cmdbuf, "sort +1 -2 +0 -1 -u -o %s %s", tocname, tocname);
  425.     X        system (cmdbuf);
  426.     X        tocfile = fopen (tocname, "r");
  427.     X        if (!tocfile)
  428.     X        {
  429.     X            fprintf (stderr, "%s: unable to read tocfile\n", pgm);
  430.     X            exit (2);
  431.     X        }
  432.     X        else
  433.     X        {
  434.     X            tocout (tocfile);
  435.     X            fclose (tocfile);
  436.     X            if (!logging) unlink (tocname);
  437.     X        }
  438.     X    }
  439.     X
  440.     X    fprintf (stdout, "\f");
  441.     X
  442.     X    exit (0);
  443.     X}
  444.     X/*Sdofile - process an input file */
  445.     X/*Hdofile*/
  446.     X/*E*/
  447.     Xdofile (fd)
  448.     XFILE    *fd;
  449.     X{
  450.     X    register int i;                 /* temporary                    */
  451.     X
  452.     X    int     lineno = 1;             /* line number in current file  */
  453.     X
  454.     X    register char *line;            /* current line pointer         */
  455.     X
  456.     X    char    ibuf[MAXWIDTH];         /* original input line          */
  457.     X    char    ebuf[MAXWIDTH];         /* line with tabs expanded      */
  458.     X
  459.     X    register char *p;               /* temporary char pointer       */
  460.     X
  461.     X    /* ------------------------------------------------------------ */
  462.     X    /* initialize the function name to `.' - unknown                */
  463.     X    /* retrieve the basename portion of the file name               */
  464.     X    /* ------------------------------------------------------------ */
  465.     X
  466.     X    strcpy (fnc_name, ".");
  467.     X
  468.     X    /* ------------------------------------------------------------ */
  469.     X    /* if building TOC, add this entry                              */
  470.     X    /* ------------------------------------------------------------ */
  471.     X
  472.     X    if (!isatty (1))
  473.     X        fprintf (tocfile,
  474.     X            "%s %s %d %d\n", fh_name, fnc_name, pageno, lineno);
  475.     X
  476.     X    /* ------------------------------------------------------------ */
  477.     X    /* if tabs are to be expanded, use the expansion buffer         */
  478.     X    /* ------------------------------------------------------------ */
  479.     X
  480.     X    if (tabstop) line = ebuf;
  481.     X    else         line = ibuf;
  482.     X
  483.     X    /* ------------------------------------------------------------ */
  484.     X    /* process each line in the file, looking for triggers          */
  485.     X    /* ------------------------------------------------------------ */
  486.     X
  487.     X    while (fgets (ibuf, MAXWIDTH, fd) NE NULL)
  488.     X    {
  489.     X        if (logging GE 9) fprintf (stderr, "%s: LOG: %s", pgm, line);
  490.     X    /* ------------------------------------------------------------ */
  491.     X    /* expand the input line                                        */
  492.     X    /* ------------------------------------------------------------ */
  493.     X
  494.     X        expand (ebuf, ibuf);
  495.     X
  496.     X        if (line[0] EQ SLASH AND line[1] EQ STAR)
  497.     X        {
  498.     X    /* ------------------------------------------------------------ */
  499.     X    /* comment found - could be a trigger                           */
  500.     X    /* ------------------------------------------------------------ */
  501.     X
  502.     X            switch (line[2])
  503.     X            {
  504.     X                case 'F':
  505.     X                case 'H':
  506.     X                {
  507.     X                    if (logging GE 9) fprintf (stderr, "F/H header\n");
  508.     X                    header (&lineno, line, fd);
  509.     X                    break;
  510.     X                }
  511.     X                case 'P':
  512.     X                {
  513.     X                    if (logging GE 9) fprintf (stderr, "page break\n");
  514.     X                    print_head ();
  515.     X                    lineno++;
  516.     X                    break;
  517.     X                }
  518.     X                case 'S':
  519.     X                {
  520.     X                    if (logging GE 9) fprintf (stderr, "subtitle\n");
  521.     X                    getname (line, subttl);
  522.     X                    lineno++;
  523.     X                    break;
  524.     X                }
  525.     X                case 'T':
  526.     X                {
  527.     X                    if (logging GE 9) fprintf (stderr, "title\n");
  528.     X                    getname (line, title);
  529.     X                    /* print_head (); */
  530.     X                    lineno++;
  531.     X                    break;
  532.     X                }
  533.     X                default:
  534.     X                {
  535.     X                    if (logging GE 9) fprintf (stderr, "other comment\n");
  536.     X                    print (&lineno, line);
  537.     X                    break;
  538.     X                }
  539.     X            }
  540.     X        }
  541.     X        else
  542.     X        {
  543.     X    /* ------------------------------------------------------------ */
  544.     X    /* not a comment - check for function declaration               */
  545.     X    /* if a form feed is found, start a new page with header        */
  546.     X    /* ------------------------------------------------------------ */
  547.     X
  548.     X            if (logging GE 9) fprintf (stderr, "not a comment\n");
  549.     X            if (!nlvl AND !isatty (1)) infunc = ckfunc (lineno, line);
  550.     X            if (*line EQ '\f') print_head ();
  551.     X            else print (&lineno, line);
  552.     X        }
  553.     X    }
  554.     X
  555.     X    page_line = LPP+1;      /* force new page after file            */
  556.     X    title[0] = NUL;         /* clear title and subtitle             */
  557.     X    subttl[0] = NUL;
  558.     X
  559.     X    return;
  560.     X}
  561.     X/*Sheader - construct and print header box */
  562.     X/*Hheader*/
  563.     X/*E*/
  564.     Xheader  (lineno, line, fd)
  565.     Xregister int     *lineno;
  566.     Xregister char    *line;
  567.     Xregister FILE    *fd;
  568.     X{
  569.     X    register char *p;
  570.     X
  571.     X    if (line[2] EQ 'F')
  572.     X    {
  573.     X        getname (line, fh_name);
  574.     X        if (BASENAME) strcpy (fh_name, basename (fh_name));
  575.     X        strcpy (fnc_name, ".");
  576.     X    }
  577.     X    else if (line[2] EQ 'H')
  578.     X    {
  579.     X        getname (line, fnc_name);
  580.     X    }
  581.     X
  582.     X    if (!isatty (1))
  583.     X        fprintf (tocfile,
  584.     X            "%s %s %d %d\n", fh_name, fnc_name, pageno, *lineno);
  585.     X
  586.     X    print_head ();
  587.     X
  588.     X    print (lineno, line);
  589.     X
  590.     X    while (fgets (line, MAXWIDTH, fd) NE NULL AND
  591.     X            notend (line))
  592.     X    {
  593.     X        if (line[0] EQ SLASH AND line[1] EQ STAR AND line[2] EQ 'P')
  594.     X        {
  595.     X            print_head ();
  596.     X            (*lineno)++;
  597.     X        }
  598.     X        else
  599.     X        {
  600.     X            print (lineno, line);
  601.     X        }
  602.     X    }
  603.     X
  604.     X    print (lineno, line);
  605.     X
  606.     X    return;
  607.     X}
  608.     X/*Sgetname - get a string from a signal line */
  609.     X/*Hgetname */
  610.     X/*E*/
  611.     Xgetname (line, name)
  612.     Xregister char    *line;
  613.     Xregister char    *name;
  614.     X{
  615.     X    register int     i;
  616.     X    register int     j;
  617.     X
  618.     X    /* ------------------------------------------------------------ */
  619.     X    /* skip leading spaces in the trigger line                      */
  620.     X    /* copy up to trailing asterisk or end-of-line                  */
  621.     X    /* strip trailing spaces                                        */
  622.     X    /* ------------------------------------------------------------ */
  623.     X
  624.     X    for (i = 3; isspace(line[i]) AND i LT MAXWIDTH; i++);
  625.     X
  626.     X    for (j = 0; line[i] AND line[i] NE '*'; i++, j++)
  627.     X    {
  628.     X        name[j] = line[i];
  629.     X    }
  630.     X
  631.     X    while (j-- GT 0 AND isspace (name[j]));
  632.     X
  633.     X    name[++j] = NUL;
  634.     X
  635.     X    return;
  636.     X}
  637.     X/*Sprint - print a line with line number */
  638.     X/*Hprint */
  639.     X/*E*/
  640.     Xprint (lineno, line)
  641.     Xregister int     *lineno;
  642.     Xregister char    *line;
  643.     X{
  644.     X    register int llen = strlen (line);
  645.     X    register int i;
  646.     X
  647.     X    register char sc = specline ? '*' : ' ';
  648.     X
  649.     X    int     j = 0;
  650.     X
  651.     X    register char    dc = NUL;
  652.     X
  653.     X    /* ------------------------------------------------------------ */
  654.     X    /* new page with header if page length is exceeded              */
  655.     X    /* ------------------------------------------------------------ */
  656.     X
  657.     X    if (page_line GT LPP)
  658.     X    {
  659.     X        print_head ();
  660.     X    }
  661.     X
  662.     X    /* ------------------------------------------------------------ */
  663.     X    /* if brace(s) found,                                           */
  664.     X    /*   modify the nesting level by the net nesting delta          */
  665.     X    /*   select the indicator according to the net delta            */
  666.     X    /*   if nexting is back to zero (none), clear function name     */
  667.     X    /* ------------------------------------------------------------ */
  668.     X
  669.     X    if (fnd (line, &j))
  670.     X    {
  671.     X        nlvl += j;
  672.     X
  673.     X        if (j LT 0) dc = '<';
  674.     X        else if (j EQ 0) dc = '*';
  675.     X        else dc = '>';
  676.     X
  677.     X        i = nlvl;
  678.     X        if (j LT 0) i++;
  679.     X        fprintf (stdout, "%4d%c%2d%c ",
  680.     X            (*lineno)++, sc, i, dc);
  681.     X        if (nlvl EQ 0) strcpy (fnc_name, ".");
  682.     X    }
  683.     X    else
  684.     X    {
  685.     X        fprintf (stdout, "%4d%c    ", (*lineno)++, sc);
  686.     X    }
  687.     X
  688.     X    /* ------------------------------------------------------------ */
  689.     X    /* break up long lines by finding the first space form the end  */
  690.     X    /* ------------------------------------------------------------ */
  691.     X
  692.     X    if (llen GT 71)
  693.     X    {
  694.     X        for (i = 70; i GE 0; i--)
  695.     X        {
  696.     X            if (line[i] EQ SPACE)
  697.     X            {
  698.     X                fprintf (stdout, "%*.*s \\\n", i, i, line);
  699.     X                page_line++;
  700.     X                break;
  701.     X            }
  702.     X        }
  703.     X
  704.     X        j = 79 - (llen - i);
  705.     X
  706.     X        for (j; j GE 0; j--) putc (SPACE, stdout);
  707.     X
  708.     X        fprintf (stdout, "%s", &line[i+1]);
  709.     X    }
  710.     X    else
  711.     X    {
  712.     X        fprintf (stdout, "%s", line);
  713.     X    }
  714.     X
  715.     X    page_line++;
  716.     X
  717.     X    specline = FALSE;       /* true if function declaration     */
  718.     X
  719.     X    return;
  720.     X}
  721.     X/*Sprint_head - print the page heading with page number */
  722.     X/*Hprint_head */
  723.     X/*E*/
  724.     Xprint_head ()
  725.     X{
  726.     X    char    headbuf[80];
  727.     X    register int len;
  728.     X
  729.     X    sprintf (headbuf, "[ %s | %s <- %s",
  730.     X        tim_lin, fh_name, fnc_name);
  731.     X
  732.     X    for (len = strlen (headbuf); len LT 68; len++) headbuf[len] = SPACE;
  733.     X
  734.     X    sprintf (&headbuf[68], "Page %-4d ]", pageno++);
  735.     X    fprintf (stdout, "\f\n");
  736.     X    if (!isatty (1))
  737.     X        fprintf (stdout, "_______________________________________\
  738.     X________________________________________");
  739.     X    fprintf (stdout, "\n%s\n", headbuf);
  740.     X    fprintf (stdout, "[-------------------------------+------\
  741.     X---------------------------------------]\n");
  742.     X
  743.     X    if (*title)
  744.     X    {
  745.     X        sprintf (headbuf, "[    %s", title);
  746.     X    }
  747.     X    else
  748.     X    {
  749.     X        sprintf (headbuf, "[    %s", fh_name);
  750.     X    }
  751.     X    for (len = strlen (headbuf); len LT 78; len++) headbuf[len] = SPACE;
  752.     X    headbuf[78] = ']';
  753.     X    fprintf (stdout, "%s\n", headbuf);
  754.     X
  755.     X    if (*subttl)
  756.     X    {
  757.     X        sprintf (headbuf, "[    %s", subttl);
  758.     X    }
  759.     X    else
  760.     X    {
  761.     X        sprintf (headbuf, "[    %s", fnc_name);
  762.     X    }
  763.     X    for (len = strlen (headbuf); len LT 78; len++) headbuf[len] = SPACE;
  764.     X    headbuf[78] = ']';
  765.     X    fprintf (stdout, "%s", headbuf);
  766.     X
  767.     X    if (!isatty (1))
  768.     X        fprintf (stdout, "\r_______________________________________\
  769.     X________________________________________");
  770.     X    fprintf (stdout, "\n\n");
  771.     X
  772.     X    page_line = LINESINHEAD;
  773.     X
  774.     X    return;
  775.     X}
  776.     X/*S fnd - return true if a brace is found */
  777.     X/*H fnd */
  778.     X/*E*/
  779.     Xfnd (in, nchg)
  780.     Xregister char *in;
  781.     Xregister int    *nchg;
  782.     X{
  783.     X#   define LBRACE   '{'
  784.     X#   define RBRACE   '}'
  785.     X#   define SHARP    '#'
  786.     X#   define COLON    ':'
  787.     X
  788.     X    register found = FALSE;         /* true if keyword found        */
  789.     X
  790.     X    register char blank = TRUE;     /* used to check for shell/make */
  791.     X                                    /* comments beginning with #/:  */
  792.     X    register int inshcomment = FALSE;   /* true if in shell comment */
  793.     X
  794.     X    *nchg = 0;              /* initialize net change to zero        */
  795.     X
  796.     X    /* ------------------------------------------------------------ */
  797.     X    /* check each character of the line                             */
  798.     X    /* ------------------------------------------------------------ */
  799.     X
  800.     X    for (in; *in; in++)
  801.     X    {
  802.     X        if (!incomment AND !inshcomment AND !indquote AND !insquote)
  803.     X        {
  804.     X            if (logging GE 9) fprintf (stderr, "not in comment or quote\n");
  805.     X            if (*in EQ SLASH AND *(in+1) EQ STAR)
  806.     X            {
  807.     X                incomment = TRUE;
  808.     X                blank = FALSE;
  809.     X                if (logging GE 9) fprintf (stderr, "new comment\n");
  810.     X            }
  811.     X            else if (blank AND
  812.     X                     ((*in EQ SHARP OR *in EQ COLON) AND
  813.     X                     (*(in+1) NE LBRACE AND *(in+1) NE RBRACE))
  814.     X                    )
  815.     X            {
  816.     X                inshcomment = TRUE;
  817.     X                blank = FALSE;
  818.     X                if (logging GE 9) fprintf (stderr, "new shell comment\n");
  819.     X            }
  820.     X            else if (*in EQ DQUOTE AND
  821.     X                    (*(in-1) NE BSLASH OR *(in-2) EQ BSLASH))
  822.     X            {
  823.     X                indquote = TRUE;
  824.     X                blank = FALSE;
  825.     X                if (logging GE 9) fprintf (stderr, "new dquote\n");
  826.     X            }
  827.     X            else if (*in EQ SQUOTE AND
  828.     X                    (*(in-1) NE BSLASH OR *(in-2) EQ BSLASH))
  829.     X            {
  830.     X                insquote = TRUE;
  831.     X                blank = FALSE;
  832.     X                if (logging GE 9) fprintf (stderr, "new squote\n");
  833.     X            }
  834.     X            else if (*in EQ LBRACE)
  835.     X            {
  836.     X                (*nchg)++;
  837.     X                found = TRUE;
  838.     X                blank = FALSE;
  839.     X                if (logging GE 9) fprintf (stderr, "nest in\n");
  840.     X            }
  841.     X            else if (*in EQ RBRACE)
  842.     X            {
  843.     X                (*nchg)--;
  844.     X                found = TRUE;
  845.     X                blank = FALSE;
  846.     X                if (logging GE 9) fprintf (stderr, "nest out\n");
  847.     X            }
  848.     X            else if (!isspace (*in))
  849.     X            {
  850.     X                blank = FALSE;
  851.     X            }
  852.     X        }
  853.     X        else if (incomment AND *in EQ STAR AND *(in+1) EQ SLASH)
  854.     X        {
  855.     X            incomment = FALSE;
  856.     X            if (logging GE 9) fprintf (stderr, "end comment\n");
  857.     X        }
  858.     X        else if (indquote AND *in EQ DQUOTE AND
  859.     X                (*(in-1) NE BSLASH OR *(in-2) EQ BSLASH))
  860.     X        {
  861.     X            indquote = FALSE;
  862.     X            if (logging GE 9) fprintf (stderr, "end dquote\n");
  863.     X        }
  864.     X        else if (insquote AND *in EQ SQUOTE AND
  865.     X                (*(in-1) NE BSLASH OR *(in-2) EQ BSLASH))
  866.     X        {
  867.     X            insquote = FALSE;
  868.     X            if (logging GE 9) fprintf (stderr, "end squote\n");
  869.     X        }
  870.     X    }
  871.     X    
  872.     X    return found;
  873.     X}
  874.     X/*Stocout - print out the table of contents */
  875.     X/*Htocout */
  876.     X/*E*/
  877.     Xtocout (toc)
  878.     XFILE    *toc;
  879.     X{
  880.     X    char    buf[80];
  881.     X    char    filenam[80];
  882.     X    char    fncnam[80];
  883.     X    int     page;
  884.     X    int     line;
  885.     X
  886.     X    char    outline[80];
  887.     X
  888.     X    register int toclines = 99;
  889.     X
  890.     X    while (fscanf (toc, "%s%s%d%d", filenam, fncnam, &page, &line) EQ 4)
  891.     X    {
  892.     X        if (toclines GT 54)
  893.     X        {
  894.     X            printf ("\f\n\
  895.     X                             _____________________\n\
  896.     X                             [ TABLE OF CONTENTS ]\r\
  897.     X                             _____________________\n\n\
  898.     X                File -> Function                     Page    Line\r\
  899.     X________________________________________\
  900.     X________________________________________\n\n");
  901.     X            toclines = 0;
  902.     X        }
  903.     X
  904.     X        toclines++;
  905.     X
  906.     X        printf ("\
  907.     X    %16s -> %-16.16s ............ %3d   %5d\n",
  908.     X            filenam, *fncnam EQ '.' ? "START" : fncnam, page, line);
  909.     X    }
  910.     X    return;
  911.     X}
  912.     X/*S expand - expand tabs to tabstop */
  913.     X/*H expand */
  914.     X/*E*/
  915.     Xexpand (to, from)
  916.     Xregister char *to;
  917.     Xregister char *from;
  918.     X{
  919.     X    register int i;
  920.     X    register int tofill;
  921.     X
  922.     X#   define BACKSPACE '\b'
  923.     X#   define FORMFEED '\f'
  924.     X#   define NEWLINE '\n'
  925.     X#   define RETURN '\r'
  926.     X#   define TAB '\t'
  927.     X    
  928.     X    i = 0;
  929.     X
  930.     X    while (*from)
  931.     X    {
  932.     X        switch (*from)
  933.     X        {
  934.     X            case    TAB:
  935.     X                tofill = tabstop - (i % tabstop);
  936.     X                i += tofill;
  937.     X                while (tofill--) *(to++) = SPACE;
  938.     X                break;
  939.     X            case    NEWLINE:
  940.     X            case    RETURN:
  941.     X                i = 0;
  942.     X            case    FORMFEED:
  943.     X                *(to++) = *from;
  944.     X                break;
  945.     X            case    BACKSPACE:
  946.     X                i--;
  947.     X                *(to++) = *from;
  948.     X                break;
  949.     X            default:
  950.     X                i++;
  951.     X                *(to++) = *from;
  952.     X                break;
  953.     X        }
  954.     X
  955.     X        from++;
  956.     X    }
  957.     X
  958.     X    *to = NUL;
  959.     X
  960.     X    return;
  961.     X}
  962.     X/*S ckfunc - check line for function declaration */
  963.     X/*H ckfunc */
  964.     X/*E*/
  965.     X
  966.     X#define isidchr(c) (isalnum(c) || (c == '_'))
  967.     X
  968.     Xckfunc (lineno, s)
  969.     Xregister int lineno;
  970.     Xregister char   *s;
  971.     X{
  972.     X    register char *p;
  973.     X    register int  Cnt;
  974.     X    register int  i;
  975.     X    register int  result;
  976.     X    register char found = FALSE;
  977.     X
  978.     X    static char *_fnm = "ckfunc";
  979.     X
  980.     X    char FunctionName[40];
  981.     X
  982.     X    if (logging GE 3)
  983.     X    {
  984.     X        fprintf (stderr,
  985.     X            "%s<%s>: LOG: ckfunc called - line = %s",
  986.     X            pgm, _fnm, s);
  987.     X    }
  988.     X
  989.     X    if(!strcmp (fnc_name, ".") AND !incomment && !indquote && !insquote)
  990.     X    {
  991.     X        found = TRUE;
  992.     X
  993.     X        while (found)
  994.     X        {
  995.     X            found = FALSE;
  996.     X            p = FunctionName;
  997.     X            for (s; isascii (*s) && isspace (*s) && *s; s++);
  998.     X            if( *s == '*' )
  999.     X            {
  1000.     X                for (++s; isascii (*s) && isspace (*s) && *s; s++);
  1001.     X            }
  1002.     X
  1003.     X            if ((*s == '_') || isalpha(*s))
  1004.     X            {
  1005.     X                while (isidchr (*s)) *p++ = *s++;
  1006.     X
  1007.     X                *p = '\0';
  1008.     X
  1009.     X                for (found = FALSE, i = 0;
  1010.     X                     !found AND ReservedWord[i]; i++)
  1011.     X                {
  1012.     X                    if (!(result = strcmp (FunctionName, ReservedWord[i])))
  1013.     X                        found = TRUE;
  1014.     X
  1015.     X                    if  (result < 0) break;
  1016.     X                }
  1017.     X
  1018.     X                if (logging GE 3 AND found)
  1019.     X                {
  1020.     X                    fprintf (stderr,
  1021.     X                        "%s<%s>: LOG: reserved word = %s\n",
  1022.     X                        pgm, _fnm, FunctionName);
  1023.     X                }
  1024.     X            }
  1025.     X        }
  1026.     X
  1027.     X        if (logging GE 3)
  1028.     X        {
  1029.     X            fprintf (stderr,
  1030.     X                "%s<%s>: LOG: last word = %s\n",
  1031.     X                pgm, _fnm, FunctionName);
  1032.     X        }
  1033.     X        
  1034.     X        for (s; isascii (*s) && isspace (*s) && *s; s++);
  1035.     X
  1036.     X        if (*s EQ '(')
  1037.     X        {
  1038.     X            for (found = FALSE; *s AND !found; s++)
  1039.     X                found = *s EQ ')';
  1040.     X            
  1041.     X            if (found)
  1042.     X            {
  1043.     X                for (; *s AND isspace (*s); s++);
  1044.     X
  1045.     X                found = *s NE ';';
  1046.     X                
  1047.     X                if (found)
  1048.     X                {
  1049.     X                    strcpy (fnc_name, FunctionName);
  1050.     X                    fprintf (tocfile,
  1051.     X                        "%s %s %d %d\n",
  1052.     X                        fh_name, fnc_name, pageno-1, lineno);
  1053.     X                    specline = TRUE;
  1054.     X                }
  1055.     X            }
  1056.     X        }
  1057.     X    }
  1058.     X
  1059.     X    if (logging GE 3)
  1060.     X    {
  1061.     X        fprintf (stderr,
  1062.     X    "%s<%s>: LOG: this line does%s contain a function declaration\n",
  1063.     X            pgm, _fnm, found ? "" : " not");
  1064.     X    }
  1065.     X
  1066.     X    return found;
  1067.     X}
  1068.     X/*S basename - return the basename part of a pathname */
  1069.     X/*H basename *********************************************************
  1070.     X*
  1071.     X*                                   basename
  1072.     X*
  1073.     X*  given a (presumed) pathname, return the part after the last slash
  1074.     X*
  1075.     X*********************************************************************/
  1076.     X/*E*/
  1077.     Xchar *
  1078.     Xbasename (str)
  1079.     Xregister char *str;
  1080.     X{
  1081.     X    register char *ret;
  1082.     X
  1083.     X    if (ret = strrchr (str, '/')) ret++;
  1084.     X    else ret = str;
  1085.     X
  1086.     X    return ret;
  1087.     X}
  1088. SHAR_EOF
  1089. if test 24738 -ne "`wc -c < 'cpg.c'`"
  1090. then
  1091.     echo shar: error transmitting "'cpg.c'" '(should have been 24738 characters)'
  1092. fi
  1093. fi # end of overwriting check
  1094. #    End of shell archive
  1095. exit 0
  1096.  
  1097.  
  1098.  
  1099.